package com.linsir.widget.form;

import com.jfinal.core.Controller;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Record;
import com.linsir.aop.AopContext;
import com.linsir.aop.MetaObjectIntercept;
import com.linsir.common.Easy;
import com.linsir.common.utils.xx;
import com.linsir.model.EovaLog;
import com.linsir.model.MetaField;
import com.linsir.model.MetaObject;
import com.linsir.service.Sm;
import com.linsir.template.common.util.TemplateUtil;
import com.linsir.widget.WidgetManager;

import java.sql.SQLException;
import java.util.ArrayList;

/**
 * @author yuxiaolin
 * @title: FormController
 * @projectName linsir-mu
 * @description: Form组件
 * @date 2021/12/2 4:06 PM
 */

public class FormController extends Controller {

    final Controller ctrl = this;

    /** 自定义拦截器 **/
    protected MetaObjectIntercept intercept = null;

    /** 异常信息 **/
    private String errorInfo = "";

    /** 当前操作的主对象 **/
    private final Record record = new Record();

    public void add() throws Exception {
        String objectCode = this.getPara(0);
        MetaObject object = Sm.meta.getMeta(objectCode);

        // 字段禁用默认对新增无效
        for (MetaField mf : object.getFields()) {
            mf.put("is_disable", false);
        }

        // 构建关联参数值
        Record fixed = WidgetManager.getRef(this);

        // 业务拦截
        intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
        if (intercept != null) {
            AopContext ac = new AopContext(ctrl);
            ac.object = object;
            ac.fixed = fixed;
            intercept.addInit(ac);
        }

        setAttr("fixed", fixed);
        setAttr("object", object);
        render("/eova/widget/form/add.html");
    }

    public void doAdd() throws Exception {

        String objectCode = this.getPara(0);

        final MetaObject object = Sm.meta.getMeta(objectCode);

        // 获取当前操作数据
        WidgetManager.buildData(this, object, record, object.getPk(), true);

        intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
        // 事务(默认为TRANSACTION_READ_COMMITTED)
        boolean flag = Db.use(object.getDs()).tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                try {
                    AopContext ac = new AopContext(ctrl, record);
                    ac.object = object;

                    // 新增前置任务
                    if (intercept != null) {
                        String msg = intercept.addBefore(ac);
                        if (!xx.isEmpty(msg)) {
                            errorInfo = msg;
                            return false;
                        }
                    }

                    if (!xx.isEmpty(object.getTable())) {
                        // add table
                        Db.use(object.getDs()).save(object.getTable(), object.getPk(), record);
                    } else {
                        // update view
                        // WidgetManager.operateView(TemplateConfig.ADD, object, record);
                        // 视图无法自动操作，请自定义元对象业务拦截完成持久化逻辑！
                    }

                    // 新增后置任务
                    if (intercept != null) {
                        String msg = intercept.addAfter(ac);
                        if (!xx.isEmpty(msg)) {
                            errorInfo = msg;
                            return false;
                        }
                    }
                } catch (Exception e) {
                    errorInfo = TemplateUtil.buildException(e);
                    return false;
                }
                return true;
            }
        });

        // 记录新增日志
        EovaLog.dao.info(this, EovaLog.ADD, object.getStr("code"));

        // 新增成功之后
        if (intercept != null) {
            try {
                ArrayList<Record> records = new ArrayList<Record>();
                records.add(record);

                AopContext ac = new AopContext(this, records);
                ac.object = object;
                String msg = intercept.addSucceed(ac);
                if (!xx.isEmpty(msg)) {
                    errorInfo = msg;
                }
            } catch (Exception e) {
                errorInfo = TemplateUtil.buildException(e);
            }
        }

        if (!xx.isEmpty(errorInfo)) {
            renderJson(Easy.fail(errorInfo));
            return;
        }

        renderJson(new Easy());
    }

    public void update() throws Exception {

        // 获取关联参数
        Record fixed = WidgetManager.getRef(this);

        AopContext ac = new AopContext(ctrl);
        ac.fixed = fixed;

        // 初始化数据
        MetaObject object = buildFormData(true, ac);
        // 业务拦截
        intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
        if (intercept != null) {
            intercept.updateInit(ac);
        }

        setAttr("fixed", fixed);

        render("/eova/widget/form/update.html");
    }

    public void doUpdate() throws Exception {

        String objectCode = this.getPara(0);

        final MetaObject object = Sm.meta.getMeta(objectCode);

        // 获取当前操作数据
        WidgetManager.buildData(this, object, record, object.getPk(), false);
        final Object pkValue = record.get(object.getPk());

        intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
        // 事务(默认为TRANSACTION_READ_COMMITTED)
        boolean flag = Db.use(object.getDs()).tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                try {
                    AopContext ac = new AopContext(ctrl, record);
                    ac.object = object;

                    // 修改前置任务
                    if (intercept != null) {
                        String msg = intercept.updateBefore(ac);
                        if (!xx.isEmpty(msg)) {
                            errorInfo = msg;
                            return false;
                        }
                    }

                    if (!xx.isEmpty(object.getTable())) {
                        // update table
                        Db.use(object.getDs()).update(object.getTable(), object.getPk(), record);
                    } else {
                        // update view
                        // WidgetManager.operateView(TemplateConfig.UPDATE, object, record);
                        // 视图无法自动操作，请自定义元对象业务拦截完成持久化逻辑！
                    }

                    // 修改后置任务
                    if (intercept != null) {
                        String msg = intercept.updateAfter(ac);
                        if (!xx.isEmpty(msg)) {
                            errorInfo = msg;
                        }
                    }
                } catch (Exception e) {
                    errorInfo = TemplateUtil.buildException(e);
                    return false;
                }
                return true;
            }

        });

        // 记录新增日志
        EovaLog.dao.info(this, EovaLog.UPDATE, object.getStr("code") + "[" + pkValue + "]");

        // 修改成功之后
        if (intercept != null) {
            try {
                ArrayList<Record> records = new ArrayList<Record>();
                records.add(record);

                AopContext ac = new AopContext(this, records);
                ac.object = object;
                String msg = intercept.updateSucceed(ac);
                if (!xx.isEmpty(msg)) {
                    errorInfo = msg;
                }
            } catch (Exception e) {
                errorInfo = TemplateUtil.buildException(e);
            }
        }

        if (!xx.isEmpty(errorInfo)) {
            renderJson(Easy.fail(errorInfo));
            return;
        }

        renderJson(new Easy());
    }

    public void detail() {
        AopContext ac = new AopContext(ctrl);
        buildFormData(false, ac);
        render("/eova/widget/form/detail.html");
    }

    /**
     * 构建对象数据
     */
    private MetaObject buildFormData(boolean isEdit, AopContext ac) {
        String objectCode = this.getPara(0);
        // 获取主键的值
        Object pkValue = getPara(1);

        MetaObject object = Sm.meta.getMeta(objectCode);
        ac.object = object;

        // 根据主键获取对象
        Record record = Db.use(object.getDs()).findById(object.getView(), object.getPk(), pkValue);

        setAttr("record", record);
        setAttr("object", object);
        ac.record = record;

        return object;
    }
}
